<template lang="">
  <table v-if="filterData.length">
    <thead>
      <tr>
        <th
          v-for="title in columns"
          @click="changeSort(title)"
          :class="{ active: sortKey == title }"
        >
          {{ upperFirst(title) }}
          <span
            class="arrow"
            :class="sortOrders[title] > 0 ? 'asc' : 'desc'"
          ></span>
        </th>
      </tr>
    </thead>
    <tbody>
      <tr v-for="row in filterData">
        <td v-for="key in columns">{{ row[key] }}</td>
      </tr>
    </tbody>
  </table>
  <div v-else>没有匹配项</div>
</template>
<script setup>
import { ref, computed, reactive } from "vue";
const props = defineProps({
  data: Array,
  columns: Array,
  filterKey: String,
});

// 排序
const sortKey = ref("");
const sortOrders = reactive(
  props.columns.reduce((obj, key) => ((obj[key] = 1), obj), {})
);
// 数据搜索
const filterData = computed(() => {
  let { data, filterKey } = props;
  // 筛选过滤
  if (filterKey) {
    filterKey = filterKey.toLowerCase();
    data = data.filter((item) => {
      return Object.keys(item).some((key) =>
        String(item[key]).toLowerCase().includes(filterKey)
      );
    });
  }
  // 排序
  let key = sortKey.value;
  if (key) {
    let orders = sortOrders[key];

    data = data.slice().sort((a, b) => {
      a = a[key];
      b = b[key];
      return (a === b ? 0 : a > b ? 1 : -1) * orders;
    });
  }

  return data;
});

// 更改排序
function changeSort(key) {
  sortKey.value = key;
  sortOrders[key] *= -1;
}
// 首字母大写
function upperFirst(str) {
  return str.charAt(0).toUpperCase() + str.slice(1);
}
</script>
<style>
table {
  border: 2px solid #42b983;
  border-radius: 3px;
  background-color: #fff;
}
th {
  background-color: #42b983;
  color: rgba(255, 255, 255, 0.65);
  cursor: pointer;
  user-select: none;
}
td {
  background-color: #f9f9f9;
}
th,
td {
  min-width: 120px;
  padding: 10px 20px;
}

th.active {
  color: #fff;
}
th.active .arrow {
  opacity: 1;
}

.arrow {
  display: inline-block;
  vertical-align: middle;
  width: 0;
  height: 0;
  margin-left: 5px;
  opacity: 0.66;
}

.arrow.asc {
  border-bottom: 4px solid #fff;
  border-left: 4px solid transparent;
  border-right: 4px solid transparent;
}
.arrow.desc {
  border-top: 4px solid #fff;
  border-left: 4px solid transparent;
  border-right: 4px solid transparent;
}
</style>
